/*******************************************************************************
* Имя файла: eightTask.cpp
* Дата: 29-05-2024
* Разработчик: Андрей Подлегаев
* Группа: 315
* Факультет: ЦДО ТУСУР
* Лицензия: BSD
* Описание: Решение задач к лабораторной работе №7 (ЦДО ТУСУР)
* *****************************************************************************/

#include "oneTask.h"
#include <typeinfo>

/* Реализация функции получения дроби */
Numbers::Fraction getFraction()
{
  print("\nОбъявим дробь:\n", COLOR_GREEN);
  //TODO (androinc@yandex.ru): Сделать проверку на выход за диапазон целого числа
  Numbers::Fraction fraction;
  int numerator, denominator;

  while(true) {

      std::cout << "Введите числитель: ";
      std::cin.unsetf(std::ios::skipws);
      if (std::cin >> numerator && std::cin.peek() == '\n')
        {
          fraction.numerator = numerator;
          std::cin.clear();
          std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
          break;
        }
      else
        {
          std::cin.clear();
          std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
          print("Введеное значение не является целым числом!\n", COLOR_RED);
          continue;
        }
    }

  while(true) {

      std::cout << "Введите знаменатель: ";
      std::cin.unsetf(std::ios::skipws);
      if (std::cin >> denominator && std::cin.peek() == '\n')
        {
          if (!denominator) {
              std::cin.clear();
              std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
              print("Введеное значение 0! Деление на ноль запрещено!\n", COLOR_RED);
              continue;
            }
          else {
              fraction.denominator = denominator;
              std::cin.clear();
              std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
              break;
            }
        }
      else
        {
          std::cin.clear();
          std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
          print("Введеное значение не является целым числом!\n", COLOR_RED);
          continue;
        }
    }

  print("Введена дробь: ", COLOR_LIGHT_GRAY);
  print(std::to_string(fraction.numerator), COLOR_GREEN);
  print("\\", COLOR_GREEN);
  print(std::to_string(fraction.denominator), COLOR_GREEN);
  println();

  return fraction;
}

/* Реализация функции получения комплексного числа */
Numbers::Complex getComplex()
{
  print("\nОбъявим комплексное число:\n", COLOR_GREEN);
  //TODO (androinc@yandex.ru): Сделать проверку на выход за диапазон целого числа
  Numbers::Complex complex;
  int re, im;

  while(true) {

      std::cout << "Введите действительную часть: ";
      std::cin.unsetf(std::ios::skipws);
      if (std::cin >> re && std::cin.peek() == '\n')
        {
          complex.Re = re;
          std::cin.clear();
          std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
          break;
        }
      else
        {
          std::cin.clear();
          std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
          print("Введеное значение не является целым числом!\n", COLOR_RED);
          continue;
        }
    }

  while(true) {

      std::cout << "Введите мнимую часть: ";
      std::cin.unsetf(std::ios::skipws);
      if (std::cin >> im && std::cin.peek() == '\n')
        {
          complex.Im = im;
          std::cin.clear();
          std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
          break;
        }
      else
        {
          std::cin.clear();
          std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
          print("Введеное значение не является целым числом!\n", COLOR_RED);
          continue;
        }
    }

  print("Введено комплексное число: ", COLOR_LIGHT_GRAY);
  print(std::to_string(complex.Re), COLOR_GREEN);
  print(" + ", COLOR_GREEN);
  print(std::to_string(complex.Im), COLOR_GREEN);
  print("i", COLOR_GREEN);
  println();

  return complex;
}

/* Реализация функции вывода в консоль */
void printResult(const double& composition)
{
  print("\nПроизведение дробей равно: ", COLOR_BLUE);
  print(std::to_string(composition), COLOR_CYAN);
  println();
}

/* Реализация функции вывода комплексного числа в консоль */
void printResult(const Numbers::Complex& composition)
{
  print("\nПроизведение комплексных чисел равно: ", COLOR_BLUE);
  print(std::to_string(composition.Re), COLOR_CYAN);
  print(" + ", COLOR_CYAN);
  print(std::to_string(composition.Im), COLOR_CYAN);
  print("i", COLOR_CYAN);
  println();
}

/* Реализация функции расчёта произведения дробей */
double multiply(void* xNumberOne, void* xNumberTwo)
{
  if (xNumberOne == nullptr || xNumberTwo == nullptr) {
      print("Ошибка ввода!", COLOR_RED);
      exit;
    }

  Numbers::Fraction* fractionOne = (Numbers::Fraction*)xNumberOne;
  Numbers::Fraction* fractionTwo = (Numbers::Fraction*)xNumberTwo;

  double composition = (static_cast<double>(fractionOne -> numerator) *
                        static_cast<double>(fractionTwo -> numerator)) /
      (static_cast<double>(fractionOne -> denominator) *
       static_cast<double>(fractionTwo -> denominator));

  return composition;
}

/* Реализация функции расчёта произведения дробей */
double multiply(const Numbers::Fraction& xFractionOne,
                const Numbers::Fraction& xFractionTwo)
{
  return (xFractionOne.numerator * xFractionTwo.numerator) /
      (xFractionOne.denominator * xFractionTwo.denominator);
}

/* Реализация функции расчёта произведения комплексных чисел */
Numbers::Complex multiplyComplex(void* xComplexOne, void* xComplexTwo)
{
  Numbers::Complex* complexOne = static_cast<Numbers::Complex*>(xComplexOne);
  Numbers::Complex* complexTwo = static_cast<Numbers::Complex*>(xComplexTwo);

  Numbers::Complex composition;

  composition.Re = complexOne -> Re * complexTwo -> Re -
      complexOne -> Im * complexTwo -> Im;
  composition.Im = complexOne -> Im * complexTwo -> Re +
      complexOne -> Re * complexTwo -> Im;

  return composition;
}

/* Реализация функции расчёта произведения комплексных чисел */
Numbers::Complex multiply(const Numbers::Complex& xComplexOne,
                          const Numbers::Complex& xComplexTwo)
{
  Numbers::Complex composition;
  composition.Re = xComplexOne.Re * xComplexTwo.Re - xComplexOne.Im * xComplexTwo.Im;
  composition.Im = xComplexOne.Im * xComplexTwo.Re + xComplexOne.Re * xComplexTwo.Im;

  return composition;
}
